/*
 @Name: color插件
 @Author: ray
 @License: MIT
*/
; rayui.define("colorutils", function (exports) {
    "use strict";

    var $ = rayui.$,
        corutils = rayui.colorutils,
        plugName = "color",
        $body = $("body"),
        $doc = $(document),
        $win = $(window),
        globalIndex = 1000,
        dataCache = {},
        dict = {},
        isOuter = false,
        timer = null,
        globalOptions = {
            event: "click", //触发方式
            width: 260,//宽度，选择框高度自动计算
            format: 'hex', //返回格式，hex、hexa、rgb、rgba、hsb、hsba
            color: '#f00',//默认颜色
            alpha: false,//是否开启透明，默认false，不开启
            preColors: false,//预先设置的颜色，在选择器下方显示，不建议设置太多
            btnClear: true,
            btnClearText: "清除",
            btnOkText: "确定"
        },
        getColorType = function (colorInput) {
            if (typeof colorInput !== "string") return null;
            if (/^#([0-9A-F]{3}|[0-9A-F]{6})$/i.test(colorInput)) return "hex";
            if (/^#([0-9A-F]{4}|[0-9A-F]{8})$/i.test(colorInput)) return "hexa";
            if (/^rgb/i.test(colorInput)) return "rgb";
            if (/^rgba/i.test(colorInput)) return "rgba";
            if (/^hsb/i.test(colorInput)) return "hsb";
            if (/^hsba/i.test(colorInput)) return "hsba";
            return null;
        },
        setBoxBgColor = function (options) {

            var rgb = corutils.hsb2rgb({ h: options.hsba.h, s: 100, b: 100 });

            //左侧选择框
            options.$sel.css("background", "rgb(" + rgb.r + "," + rgb.g + "," + rgb.b + ")");

            //透明渐变
            if (options.alpha) {
                options.$alphabg.css("background", "linear-gradient(to right, rgba(" + rgb.r + ", " + rgb.g + ", " + rgb.b + ",0), rgb(" + rgb.r + ", " + rgb.g + ", " + rgb.b + "))");
            }
        },
        changing = function (options) {

            var cc;
            switch (options.format) {
                case "hex":
                default:
                    options.inputText = "#" + corutils.hsb2hex(options.hsba);
                    break;
                case "hexa":
                    var ahex = Math.round(options.hsba.a * 255).toString(16);
                    if (ahex.length === 1) ahex = "0" + ahex;
                    options.inputText = "#" + corutils.hsb2hex(options.hsba) + ahex;
                    break;
                case "rgb":
                    cc = corutils.hsb2rgb(options.hsba);
                    options.inputText = "rgb(" + cc.r + "," + cc.g + "," + cc.b + ")";
                    break;
                case "rgba":
                    cc = corutils.hsb2rgb(options.hsba);
                    options.inputText = "rgba(" + cc.r + "," + cc.g + "," + cc.b + "," + options.hsba.a + ")";
                    break;
                case "hsb":
                    options.inputText = "hsb(" + options.hsba.h + "," + options.hsba.s + "," + options.hsba.b + ")";
                    break;
                case "hsba":
                    options.inputText = "hsb(" + options.hsba.h + "," + options.hsba.s + "," + options.hsba.b + "," + options.hsba.a + ")";
                    break;
            }

            options.$input.val(options.inputText);

            if (options.first) {
                typeof options.onChanging === "function" && options.onChanging(options.inputText);
            } else {
                options.first = true;
            }
        },
        sideMove = function (options, e) {
            var top = e.pageY - options.$sidebg.offset().top,
                bgH = options.$sidebg.outerHeight();

            if (top < 0) top = 0;
            if (top > bgH) top = bgH;

            options.$side.css("top", top + "px");

            options.hsba.h = top * 360 / bgH;

            setBoxBgColor(options);
            changing(options);
        },
        alphaMove = function (options, e) {
            var boxW = options.$alphabg.outerWidth();
            var tmp = e.pageX - options.$alphabg.offset().left;
            if (tmp < 0) {
                tmp = 0;
                options.hsba.a = 0;
            }
            else if (tmp >= boxW) {
                tmp = boxW;
                options.hsba.a = 1;
            } else
                options.hsba.a = Math.round((tmp / boxW) * 100) / 100;

            options.$alpha.css("left", tmp > boxW ? boxW : tmp + "px");
            changing(options);
        },
        selMove = function (options, e) {
            var offset = options.$sel.offset(),
                left = e.pageX - offset.left,
                top = e.pageY - offset.top,
                w = options.$sel.outerWidth(),
                h = options.$sel.outerHeight();

            if (left < 0) left = 0;
            if (left > w) left = w;
            if (top < 0) top = 0;
            if (top > h) top = h;

            options.hsba.s = Math.round(left * 100 / w);
            options.hsba.b = Math.round(100 - top * 100 / h);

            options.$circle.css({
                left: left,
                top: top
            });
            changing(options);
        },
        DealHandle = function (options) {
            var that = this;
            that.index = globalIndex;

            that.options = options = $.extend(true, {}, globalOptions, options);
            options.preColors === true && (options.preColors = ["#f00", "#FFA300", "#129A00", "#108B81", "#1768E9", "#8116E2", "#D510C0", "#3E8C55"]);

            DealHandle.utils.init.call(that);
            DealHandle.utils.addEvents.call(that);
            DealHandle.utils.setColor.call(that, options.color);
        };


    DealHandle.utils = {
        init: function () {
            var that = this,
                options = that.options;

            options.$main = $('<div class="rayui-color-box"/>').outerWidth(options.width);
            $(options.container).length > 0
                ? options.$main.css("position", "relative").appendTo($(options.container))
                : options.$main.appendTo($body);

            var $selbox = $('<div class="color-select-box"/>').appendTo(options.$main);
            //选择框
            options.$sel = $('<div class="color-select"/>').appendTo($selbox);
            options.$sel.append('<div class="color-basic-white"/><div class="color-basic-black"/>');
            options.$circle = $('<div class="color-circle"/>').appendTo(options.$sel);

            //右侧滑块
            var $sidebox = $('<div class="color-side"/>').appendTo($selbox);
            options.$sidebg = $('<div class="color-side-bg"/>').appendTo($sidebox);
            options.$side = $('<div class="color-h"/>').appendTo($sidebox);

            //设置宽度
            var selW = options.$main.width() - options.$side.width() - 7;
            $selbox.height(selW / 1.44);
            options.$sel.width(selW);

            //透明度
            if (options.alpha) {
                options.$alphabox = $('<div class="color-alpha-box"/>').appendTo(options.$main);
                options.$alphabg = $('<div class="color-alpha-bg"/>').appendTo(options.$alphabox);
                options.$alpha = $('<div class="color-alpha"/>').appendTo(options.$alphabox);
            }

            //预设颜色
            if (options.preColors) {
                options.$predefbox = $('<div class="color-predef-box"/>').appendTo(options.$main);
                $.each(options.preColors, function (a, b) {
                    options.$predefbox.append('<div class="color-predef" data-color="' + b + '" style="background:' + b + '"></div>');
                });
            }

            //tool，显示框 清除确定按钮
            options.$tool = $('<div class="color-tool-box"/>').appendTo(options.$main);
            options.$input = $('<input type="text" class="color-input"/>').appendTo(options.$tool);
            var $btns = $('<div class="color-btn-box"/>').appendTo(options.$tool);
            options.btnClear && (options.$btnClear = $('<button class="rayui-btn btn-clear">' + options.btnClearText + '</button>').appendTo($btns));
            options.$btnok = $('<button class="rayui-btn btn-success btn-ok">' + options.btnOkText + '</button>').appendTo($btns);

            $(options.container).length === 0 && options.$main.hide();
        },
        show: function () {

            var that = this,
                options = that.options;

            //隐藏其他
            rayui.toggleDocEvt();

            if (options.container) return;

            options.$main.show();
            DealHandle.utils.position.call(that);
        },
        position: function () {
            var that = this,
                options = that.options;
            //容器内的和不显示的直接返回
            if (options.container || !options.$main.is(':visible')) return;
            
            //计算定位，原则优先下方左对齐
            var $elem = $(options.elem),
                ew = $elem.outerWidth(),
                eh = $elem.outerHeight(),
                eo = $elem.offset(),
                vs = $doc.scrollTop(), //竖向滚动条
                hs = $doc.scrollLeft(), //横向滚动条
                w = $win.width(),
                h = $win.height(),
                mw = options.$main.outerWidth(), //main宽度
                mh = options.$main.outerHeight(),
                opt = { bottom: 'auto', top: 'auto'};//main高度
            options.$main.hide();
            
            if (eo.top - vs + eh + mh > h)
                opt.bottom = h - eo.top + 3;//上方显示
            else
                opt.top = eo.top + eh + 3;//下方显示
            opt.left = eo.left - hs + mw > w ? eo.left + ew - mw//右对齐
                : eo.left;//左对齐
            options.$main.css(opt).slideDown(200);
        },
        hide: function () {
            var that = this,
                options = that.options;

            if (options.container) return;
            options.$main.hide();
        },
        setColor: function (color) {

            var that = this,
                options = that.options,
                isvisible = options.$main.is(":visible"),  m, rgb;

            var type = getColorType(color);
            if (type == null) color = "#f00";//默认红色

            switch (type) {
                case "hex":
                    options.hsba = corutils.hex2hsb(color);
                    options.alpha && (options.hsba.a = 1);
                    break;
                case "hexa":
                    var ahex = "";
                    if (color.length === 5) {
                        ahex = color.substr(4, 1);
                        ahex += ahex;
                        color = color.substr(0, 4);
                    } else {
                        ahex = color.substr(7, 2);
                        color = color.substr(0, 7);
                    }
                    var a = parseInt(ahex, 16);
                    options.hsba = corutils.hex2hsb(color);
                    if (options.alpha) {
                        options.hsba.a = a / 100;
                    }
                    break;
                case "rgb":
                case "rgba":
                    m = color.match(/\d+/g);
                    rgb = {
                        r: parseInt(m[0]),
                        g: parseInt(m[1]),
                        b: parseInt(m[2])
                    }
                    options.hsba = corutils.rgb2hsb(rgb);
                    if (options.alpha) {
                        options.hsba.a = m.length === 4 ? Math.round(parseFloat(m[3]) * 100) / 100 : 1;
                    }
                    break;
                case "hsb":
                case "hsba":
                    m = color.match(/\d+/g);
                    options.hsba = {
                        h: parseInt(m[0]),
                        s: parseInt(m[1]),
                        b: parseInt(m[2])
                    }

                    if (options.alpha) {
                        options.hsba.a = m.length === 4 ? Math.round(parseFloat(m[3]) * 100) / 100 : 1;
                    }
                    break;
            }

            //设置各个区域
            if (!isvisible) options.$main.show();
            //h
            var hsba = options.hsba,
                sideH = options.$sidebg.outerHeight(),
                top = hsba.h * sideH / 360;
            options.$side.css("top", top + "px");
            setBoxBgColor(options);

            //s b
            var selW = options.$sel.outerWidth(),
                selH = options.$sel.outerHeight(),
                s = hsba.s * selW / 100,
                b = selH - hsba.b * selH / 100;

            options.$circle.css({ left: s + "px", top: b + "px" });

            //a
            if (options.alpha) {
                var boxW = options.$alphabg.outerWidth(),
                    left = options.hsba.a * boxW;
                options.$alpha.css("left", left + "px");
            }

            //text
            changing(options);

            if (!isvisible) options.$main.hide();
        },
        addEvents: function () {
            var that = this,
                options = that.options;

            //阻止冒泡
            options.$main.on("click." + plugName, function (e) {
                e.stopPropagation();
            });

            //触发事件
            $(options.elem).on(options.event + "." + plugName, function (e) {
                e.stopPropagation();
                DealHandle.utils.show.call(that);
            });

            //左侧选择滑动
            options.$sel.on("mousedown." + plugName, function (e) {
                dict = {
                    type: 1,
                    options: options
                };

                selMove(options, e);
                e.preventDefault();
            });

            //右侧颜色条滑动
            options.$sidebg.on("mousedown." + plugName, function (e) {
                dict = {
                    type: 2,
                    options: options
                };
                $body.css("cursor", "s-resize");
                sideMove(options, e);
                e.preventDefault();
            });

            //透明度条滑动
            if (options.alpha) {
                options.$alphabox.on("mousedown." + plugName, function (e) {
                    dict = {
                        type: 3,
                        options: options
                    };
                    $body.css("cursor", "pointer");
                    alphaMove(options, e);
                    e.preventDefault();
                });
            }

            //预设颜色
            if (options.preColors) {
                options.$predefbox.find('.color-predef').click(function () {
                    var color = $(this).data("color");
                    DealHandle.utils.setColor.call(that, color);
                });
            }

            //按钮事件
            options.btnClear && options.$btnClear.click(function () {
                options.inputText = "";
                options.$input.val(options.inputText);
                typeof options.onChanging === "function" && options.onChanging(options.inputText);
                typeof options.onChanged === "function" && options.onChanged(options.inputText);
                DealHandle.utils.hide.call(that);
            });
            options.$btnok.click(function () {
                DealHandle.utils.hide.call(that);
                typeof options.onChanged === "function" && options.onChanged(options.inputText);
            });
        }
    }

    $doc.on("mousemove." + plugName, function (e) {
        if (!dict) return;
        if (dict.type === 1) selMove(dict.options, e);
        else if (dict.type === 2) sideMove(dict.options, e);
        else if (dict.type === 3) alphaMove(dict.options, e);
    }).on("mouseup." + plugName, function () {
        dict = null;
        $body.css("cursor", "default");
    });

    rayui.bindDocEvt(plugName, function () {
        if (isOuter) return;

        //隐藏所有非container颜色框
        for (var key in dataCache) {
            DealHandle.utils.hide.call(dataCache[key]);
        }
    });

    //自适应定位
    $win.on('resize', function () {
        //调整显示位置
        if (timer != null) clearTimeout(timer);
        timer = setTimeout(function () {
            timer = null;
            for (var key in dataCache) {
                DealHandle.utils.position.call(dataCache[key]);
            }
        }, 200);
        
    });

    DealHandle.prototype = {
        on: function (event, func) {
            if (typeof event !== "string" || typeof func !== "function") return;
            var that = this,
                options = that.options;

            if (event === "changing") options.onChanging = func;
            else if (event === "changed") options.onChanged = func;
        },
        off: function (event) {
            if (typeof event !== "string") return;
            var that = this,
                options = that.options;

            if (event === "changing") options.onChanging = null;
            else if (event === "changed") options.onChanged = null;
        },
        show: function () {
            isOuter = true;
            DealHandle.utils.show.call(this);
            setTimeout(function () { isOuter = false;}, 100);
        },
        hide: function () {
            DealHandle.utils.hide.call(this);
        },
        setColor: function (color) {
            DealHandle.utils.setColor.call(this, color);
        }
    }

    var colorpg = {
        options: globalOptions,
        render: function (options) {
            if ($(options.elem).length === 0 && $(options.container).length === 0) return "DOM对象不存在";

            var cc = new DealHandle(options);
            dataCache[globalIndex++] = cc;
            return cc;
        }
    };

    exports(plugName, colorpg);
}, rayui.jsAsync());
